package com.xuecheng.base.exception;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

/**
 * 全局异常处理器（AOP面向切面编程思想）
 * RestControllerAdvice 相当于@ControllerAdvice + @ResponseBody
 * ResponseStatus 用状态码和应返回的原因标记方法或异常类。调用处理程序方法时，状态码将应用于HTTP响应
 * ControllerAdvice 用于指定哪些注解标识的类发生异常时需要被通知
 * ResponseBody 用于将结果封装为JSON数据进行返回
 * Slf4j 用于输出一些信息到控制台（服务器）
 */
@Slf4j
@RestControllerAdvice
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 该异常枚举错误码为500
public class GlobalExceptionHandler {

    /**
     * ExceptionHandler(XueChengPlusException.class) 处理这种自定义异常
     *
     * @param e 注入异常对象
     * @return 响应用户的统一类型
     */
    @ExceptionHandler(XueChengPlusException.class)
    public RestErrorResponse exceptionHandler(XueChengPlusException e) {
        log.error("[系统异常] {}", e.getErrMessage());
        return new RestErrorResponse(e.getErrMessage());
    }

    /**
     * ExceptionHandler(Exception.class) 处理其他异常
     *
     * @param e 注入异常对象
     * @return 响应用户的统一类型
     */
    @ExceptionHandler(Exception.class)
    public RestErrorResponse exception(Exception e) {
        log.error("[其他异常] {}", e.getMessage());
        if (e.getMessage().contains("不允许访问")) {
            return new RestErrorResponse("您没有权限操作此功能");
        }
        return new RestErrorResponse("未知异常，请稍后重试");
    }

    /**
     * ExceptionHandler(MethodArgumentNotValidException) 处理JSR303异常
     *
     * @param e 注入异常对象
     * @return 响应用户的统一类型
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestErrorResponse methodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 获取错误消息
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

        // 错误消息集合
        List<String> msgList = new ArrayList<>();

        // 将每条错误消息都添加到错误消息集合中
        fieldErrors.forEach(item -> msgList.add(item.getDefaultMessage()));

        // 拼接消息集合中的错误消息
        String msg = StringUtils.join(msgList, ",");

        log.error("[JSR303异常] {}", msg);
        return new RestErrorResponse(msg);
    }
}
